package com.leo.train.business.service.Impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.leo.train.business.dto.DailyTrainQueryDto;
import com.leo.train.business.entity.DailyTrain;
import com.leo.train.business.entity.Train;
import com.leo.train.business.mapper.DailyTrainMapper;
import com.leo.train.business.mapper.TrainMapper;
import com.leo.train.business.service.*;
import com.leo.train.business.vo.DailyTrainQueryVo;
import com.leo.train.common.enums.TrainTypeEnum;
import com.leo.train.common.exception.BusinessException;
import com.leo.train.common.exception.BusinessExceptionEnum;
import com.leo.train.common.resp.PageResult;
import com.leo.train.common.util.SnowUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

@Service
@Slf4j
public class DailyTrainServiceImpl implements DailyTrainService {
    @Autowired
    private DailyTrainMapper dailyTrainMapper;
    @Autowired
    private TrainMapper trainMapper;
    @Autowired
    private DailyTrainInfoService dailyTrainInfoService;
    @Autowired
    private DailyCarriageService dailyCarriageService;
    @Autowired
    private DailySeatService dailySeatService;
    @Autowired
    private DailyTrainTicketService dailyTrainTicketService;
    @Autowired
    private SkTokenService skTokenService;
    /**
     * 保存车次
     * @param dailyTrain
     */
    @Override
    public void save(DailyTrain dailyTrain) {
        Long id = dailyTrain.getId();
        if(id == null) {
            // 判断该车次是否已经存在
            DailyTrain dailyTrainExist =  selectByCodeAndDate(dailyTrain.getCode(), dailyTrain.getDate());
            if(dailyTrainExist != null) {
                throw new BusinessException(BusinessExceptionEnum.BUSINESS_TRAIN_CODE_UNIQUE_ERROR);
            }
            // 新增
            dailyTrain.setId(SnowUtil.getSnowflakeNextId());
            dailyTrain.setCreateTime(new Date());
            dailyTrain.setUpdateTime(new Date());
            dailyTrainMapper.insert(dailyTrain);
        } else {
            // 编辑
            dailyTrain.setUpdateTime(new Date());
            dailyTrainMapper.update(dailyTrain);
        }

    }

    /**
     * 查询车次列表
     * @param dailyTrainQueryDto
     * @return
     */
    @Override
    public PageResult<DailyTrainQueryVo> list(DailyTrainQueryDto dailyTrainQueryDto) {
        PageHelper.startPage(dailyTrainQueryDto.getPage(), dailyTrainQueryDto.getPageSize());
        Page<DailyTrain> page = dailyTrainMapper.pageQuery(dailyTrainQueryDto);
        // 遍历列表，为列表多返回一个类型名称
        List<DailyTrainQueryVo> dailyTrainQueryVoList = page.getResult().stream().map(dailyTrain -> {
            DailyTrainQueryVo dailyTrainQueryVo = new DailyTrainQueryVo();
            BeanUtils.copyProperties(dailyTrain, dailyTrainQueryVo);
            dailyTrainQueryVo.setTypeName(TrainTypeEnum.fromCode(dailyTrain.getType()).getDescription());
            return dailyTrainQueryVo;
        }).collect(Collectors.toList());

        return new PageResult(page.getTotal(), dailyTrainQueryVoList);
    }

    @Override
    public DailyTrainQueryVo detail(Long id) {
        DailyTrain dailyTrain = dailyTrainMapper.selectById(id);
        if(dailyTrain == null) {
            throw new BusinessException(BusinessExceptionEnum.BUSINESS_TRAIN_NOT_EXIST);
        }
        DailyTrainQueryVo dailyTrainQueryVo = new DailyTrainQueryVo();
        BeanUtils.copyProperties(dailyTrain, dailyTrainQueryVo);
        dailyTrainQueryVo.setTypeName(TrainTypeEnum.fromCode(dailyTrain.getType()).getDescription());
        return dailyTrainQueryVo;
    }

    @Override
    public void delete(Long id) {
        dailyTrainMapper.deleteById(id);
    }

    @Override
    public List<DailyTrain> listAll() {
        return dailyTrainMapper.selectAll();
    }

    /**
     * 生成某日所有车次
     * @param date
     */
    @Override
    @Transactional
    public void genDaily(Date date) {
        // 1. 查询所有车次  -- 查基本数据
        List<Train> trainList = trainMapper.selectAll();
        if(CollUtil.isEmpty(trainList)) {
            log.info("没有车次基础数据");
            return;
        }
        // 2. 循环遍历车次
        for(Train train : trainList) {
            // 2.1 先删除再生成该车次的数据
            genDailyTrain(train, date);
        }
        log.info("生成某日所有车次结束，date: {}", DateUtil.formatDate(date));
    }

    public void genDailyTrain(Train train, Date date) {
        log.info("生成某日车次开始，train: {}, date: {}", train.getCode(), DateUtil.formatDate(date));
        Date now = new Date();
        // 2.1 先删除该车次已有的数据   (该车次,该时间的数据)
        dailyTrainMapper.deleteByTrainCodeAndDate(train.getCode(), date);
        // 2.2 生成该车次的数据
        DailyTrain dailyTrain = new DailyTrain();
        BeanUtils.copyProperties(train, dailyTrain);
        dailyTrain.setId(SnowUtil.getSnowflakeNextId());
        dailyTrain.setCreateTime(now);
        dailyTrain.setUpdateTime(now);
        dailyTrain.setDate(date);
        dailyTrainMapper.insert(dailyTrain);

        // 2.3 生成当前车次的所有车站数据
        dailyTrainInfoService.genDaily(date, train.getCode());


        // 2.4 生成当前车次所有车厢数据
        dailyCarriageService.genDaily(date, train.getCode());

        // 2.5 生成当前车次所有座位数据
        dailySeatService.genDaily(date, train.getCode());

        // 2.6 生成当前车次所有车票数据
        // 生成该车次的余票数据
        dailyTrainTicketService.genDaily(dailyTrain, date, train.getCode());

        // 2.7 生成当前车次的令牌数据
        skTokenService.genDaily(date, train.getCode());

        log.info("生成某日车次结束，train: {}, date: {}", train.getCode(), DateUtil.formatDate(date));
    }

    /**
     * 定义一个唯一键方法
     */
    public DailyTrain selectByCodeAndDate(String code, Date date) {
        DailyTrain dailyTrain = dailyTrainMapper.selectByCodeAndDate(code, date);
        if (dailyTrain != null) {
            return dailyTrain;
        }
        return null;
    }
}
